package com.happysmile.ipblock;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.happysmile.ipblock.config.NeedEnhance;
import com.happysmile.ipblock.mybatis.entity.Ip;
import com.happysmile.ipblock.mybatis.mapper.IpMapper;
import com.happysmile.ipblock.outter.R;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.junit.Test;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;

@RestController
@SpringBootApplication
@RequestMapping("/ip")
@MapperScan("com.happysmile.ipblock.mybatis.mapper")
public class IpblockApplication {

    public static void main(String[] args) {
        SpringApplication.run(IpblockApplication.class, args);
    }


    @NeedEnhance(isAchieve = false,why = "1.执行Sql脚本，进行物理封禁（缺少这种操作）",version = "1")
    @ApiOperation(value = "封禁ip",notes = "封禁用户ip。该用户的所有请求都会被封禁。并且加入到ip黑名单数据库中。")
    @GetMapping("/ban/{ips}")
    public R ip_ban(@PathVariable @ApiParam("禁用的ip。支持格式:ip1,ip2,ip3。以,分割") String ips){
        String[] split = ips.split(",");
        StringBuilder sb = new StringBuilder();
        int count = 0;//成功封禁ip的数量
        for (String ip:split){
            //得到每一个ip
            //从数据库中查询该ip是否存在
            if (!isExits(ip)) {sb.append("ip: " + ip + " 未入库").append("    ");continue;}
            //从数据库中查询该ip是否封禁
            // 如果已封禁，则返回对应状态
            if (isBaned(ip)) {sb.append("ip: " + ip + " 已被封禁").append("    ");continue;}
            try {
                // 如果未封禁，将其添加到黑名单数据库
                ipMapper.update(null,new UpdateWrapper<Ip>()
                        .set("is_ban",1).set("modify_reason","封禁ip").eq("ip",ip));
                //执行Sql脚本，进行物理封禁
            }catch (Exception e){
                sb.append("ip: " + ip + "更新失败").append("    ");
                continue;
            }
            count++;
        }
        return R.success(count + "个ip被封禁。" + sb.toString());
    }

    @NeedEnhance(isAchieve = false,why = "1.执行Sql脚本，进行物理封禁（缺少这种操作）",version = "1")
    @ApiOperation(value = "解封ip",notes = "解封用户的ip。从ip封禁的黑名单数据库中删除该ip")
    @GetMapping("/unban/{ips}")
    public R ip_unban(@PathVariable @ApiParam("解封的ip。支持格式:ip1,ip2,ip3。以,分割") String ips){
        String[] split = ips.split(",");
        StringBuilder sb = new StringBuilder();
        int count = 0;//成功解封ip的数量
        for (String ip:split){
            //从数据库中查询该ip是否存在
            if (!isExits(ip)) {sb.append("ip: " + ip + " 未入库").append("    ");continue;}
            //从数据库中查询该ip是否封禁
            //如果未封禁，返回对应状态
            if (!isBaned(ip)) {sb.append("ip: " + ip + " 未被封禁").append("    ");continue;}
            // 如果已封禁，将其从黑名单数据库解封，返回对应的状态
            try {
                ipMapper.update(null,new UpdateWrapper<Ip>()
                        .set("is_ban",0).set("modify_reason","解封ip").eq("ip",ip));
                //执行Sql脚本，进行物理解封
            }catch (Exception e){
                sb.append("ip: " + ip + "更新失败").append("    ");
                continue;
            }
            count ++;
        }
        return R.success(count + "个ip被解封。" + sb.toString());
    }

    @ApiOperation(value = "ip黑名单撞库",notes = "采用逆向工程的方法，从其他DDos防御平台获取到查询ip黑名单的数据库接口，如果查到了该ip,则对该ip进行请求的降级。")
    @GetMapping(value = "/blacklist_crossdatabasequery/{ips}")
    public void blacklist_crossdatabasequery(@PathVariable @ApiParam("查询的ip--意图:是否在其他库中被封禁") String ips){
        //将ips转化为有序，唯一，查找效率和插入删除效率高的数据结构
        LinkedHashSet<String> ipsUnique = new LinkedHashSet<String>();
        for (String ip:ips.split(",")){
            ipsUnique.add(ip);
        }
        //1.连接任意一个黑名单数据库
            //这一步可以模拟注册，登录，使用系统正常的功能。
            //因此封装成业务代码单独调用
            //方法返回1个url，1种认证策略
        //2.根据ips查询对应的结果
            //2.1 该ip被其封禁，则调用ip_ban()封禁
            //2.2 该ip未被其封禁，返回未封禁
    }


    /*
    * https://www.yundun.com/ 模拟查询 测试
    * */
    @Test
    public void query_yundun_Test(){
        //1.注册 -- 写死
        //采用临时邮箱 + 临时短信验证码进行注册
        //neafxs26173@chacuo.net
        //Ddos2021 --AES pwd
        //5L2g5Y+v5Lul55So5LiK6Z2i55qE5a+G56CB5p2l5L2c5Li6QUVT5Yqg5a+G55qE5a+G6ZKl44CC

        /*
        U2FsdGVkX19LB1dxbUrcp0Q1/hX7yUasglvBgDS1rtOOk81Nx6QCScxddSN0/Dro
        JzcvwtViuqspe+8uXE/AAh1xnEfEerqaw9j/T+d+hXrNcc8AXZ6N9XTZYizuBH4K
        hc1XlWCZbju/o4t163tV7zp7jpgq2usOsteOam6g2k48BTFpkdyDpSi1kv5zmNr2
        */
    }




    @ApiOperation(value = "批量录入ip",notes = "根据传入的ip插入到数据库，返回插入的条数")
    @PostMapping("/add")
    public R<Integer> add(@RequestBody List<Ip> ips){
        Integer integer = insertIps(ips);
        if (integer == -1){
            return R.fail("该ip已存在");
        }else if (integer != ips.size()){
            return R.fail("仅" +integer + "条ip插入成功");
        }else {
            return R.success(integer);
        }
    }



    @ApiOperation(value = "查询所有ip信息")
    @GetMapping("/list")
    public R<List<Ip>> findIps(){
        List<Ip> ips = ipMapper.selectList(null);
        return R.success(ips);
    }

    @Resource
    private IpMapper ipMapper;

    /*
    * 插入数据。成功返回插入的条数，失败返回-1
    * */
    @Transactional(rollbackFor = Exception.class)
    Integer insertIps(List<Ip> ips){
        //如果传入0个ip,则返回-1
        if (ips.size() == 0) return -1;
        Iterator<Ip> it = ips.iterator();
        Integer res = 0;
        while (it.hasNext()) {
            Ip nextIp = it.next();
            try {
                res += ipMapper.insert(nextIp);
            }catch (Exception e){
                //如果有插入失败的记录，在这里捕获，最终根据结果判定成功了多少条。
                //如果后期有想做更多逻辑，可以在这里发挥
                continue;
            }
        }
        return res == ips.size()? res : (res == 0) ? -1 : res;
    }



   /*
   * 查询ip是否被禁
   * */
    @Transactional(rollbackFor = Exception.class)
    Boolean isBaned(String ip){
        Ip res = ipMapper.selectOne(new QueryWrapper<Ip>().select("is_ban").eq("ip", ip));
        if (res.getIsBan())
            return Boolean.TRUE;
        else
            return Boolean.FALSE;
    }

    /*
    * 查询ip是否存在
    * */
    @Transactional(rollbackFor = Exception.class)
    Boolean isExits(String ip){
        Ip res = ipMapper.selectOne(new QueryWrapper<Ip>().eq("ip", ip));
        if (res != null)
            return Boolean.TRUE;
        else
            return Boolean.FALSE;
    }


}